package com.yeung.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class CalculatorProxy {
    //要代理的对象
    private ArtithmeticCalculatorImp target;

    public CalculatorProxy(ArtithmeticCalculatorImp calculator) {
        this.target = calculator;
    }

    /**
     * 返回一个代理对象
     *
     * @return
     */
    public ArtithmeticCalculator getLoggingProxy() {
        ArtithmeticCalculator proxy = null;
        //代理对象由哪一个类加载器负责加载
        ClassLoader classLoader = target.getClass().getClassLoader();
        //代理对象的类型,即其中有哪些方法   只能是接口类!!!
        Class[] interfaces = new Class[]{ArtithmeticCalculator.class};
        //当调用代理对象其中的方法时,执行该handler
        InvocationHandler h = new InvocationHandler() {
            /**
             *
             * @param proxy 一般情况下正在返回的那个代理对象,一般情况下,再invoke方法中都不使用该对象
             *              他是一个代理对象,一调用它的方法又会进入代理,是个死循环
             * @param method 正在被调用的方法
             * @param args 调用方法是,传入的参数
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //日志
                System.out.println("the mehthod: " + method.getName() + " is starting...");
                //执行方法
                Object result = null;
                try {
                    //前置通知
                    result = method.invoke(target, args);
                    //返回通知,可以访问得到方法的返回值
                } catch (Exception e) {
                    //异常通知,可以访问到方法出现的异常
                }
                //后置通知,因为方法可能会出异常,所以访问不到方法的返回值
                //日志
                System.out.println(" the method is completed");
                return result;
            }
        };
        //返回这个代理对象, 这个代理对象被执行的时候, 会调用其中复写的
        //invoke方法, 就可以  添加其他附加的业务逻辑
        proxy = (ArtithmeticCalculator) Proxy.newProxyInstance(classLoader, interfaces, h);
        return proxy;
    }
}
